package com.liuche.homechat.common.user.service.impl;

import com.liuche.homechat.common.common.config.ThreadPoolConfig;
import com.liuche.homechat.common.user.enums.ItemEnum;
import com.liuche.homechat.common.user.enums.ItemTypeEnum;
import com.liuche.homechat.common.user.dao.UserDao;
import com.liuche.homechat.common.user.domain.entity.User;
import com.liuche.homechat.common.user.service.UserRoleService;
import com.liuche.homechat.common.user.service.UserBackpackService;
import com.liuche.homechat.common.user.service.UserService;
import com.liuche.homechat.common.user.service.WXMsgService;
import com.liuche.homechat.common.user.service.adapter.TextBuilder;
import com.liuche.homechat.common.websocket.service.CustomWebSocketService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.net.URLEncoder;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author：liuche
 * @Date：2024年05月26日 21:14
 * @Description：
 */
@Service
@Slf4j
public class WXMsgServiceImpl implements WXMsgService {
    // 这里最好也用 caffeine 去做
    private static final Map<String, String> OPENID_CODE_MAP = new ConcurrentHashMap<>();

    private static final String URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";
    @Value("${wx.mp.callback}")
    private String callback;
    @Resource
    private UserService userService;
    @Resource
    private UserDao userDao;

    @Resource
    @Lazy
    private CustomWebSocketService customWebSocketService;
    @Resource
    private UserBackpackService userBackpackService;
    @Resource(name = ThreadPoolConfig.HOMECHAT_EXECUTOR)
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Resource
    private UserRoleService userRoleService;


    @Override
    public WxMpXmlOutMessage handleScan(WxMpXmlMessage wxMpXmlMessage, Map<String, Object> map, WxMpService wxMpService, WxSessionManager wxSessionManager) {
        // 扫码事件处理
        log.info("接收到用户的扫码，wxMpXmlMessage->[{}],map->[{}]", wxMpXmlMessage, map);
        String openID = wxMpXmlMessage.getFromUser();
        String code = getEventKey(wxMpXmlMessage);

        if (StringUtils.isBlank(code)) {
            return TextBuilder.build("感谢关注，会持续为您输出有趣的文章！", wxMpXmlMessage);
        }

        // 根据 openID 查询用户
        User user = userService.queryUserByOpenID(openID);

        if (ObjectUtils.isNotEmpty(user) && StringUtils.isNotBlank(user.getAvatar())) {
            // 该用户已经注册过，进行登陆操作 todo
            customWebSocketService.authorize(user.getId(), code);
            return TextBuilder.build("欢迎登录！", wxMpXmlMessage);
        } else {
            // 保存 openID 和对应的 code 信息
            OPENID_CODE_MAP.put(openID, code);

            if (ObjectUtils.isEmpty(user)) {
                // 新用户扫码过来要登录的
                userService.addUser(openID);
                customWebSocketService.promptUserAuthorize(code);
                String authorizeURL = String.format(URL,wxMpService.getWxMpConfigStorage().getAppId(), URLEncoder.encode(callback + "/wx/portal/public/callBack"));
                return TextBuilder.build("欢迎光临👏👏👏请点击链接授权：<a href=\"" + authorizeURL + "\">点我授权</a>", wxMpXmlMessage);
            }
        }

        // web 端提示用户注意微信端的授权
        customWebSocketService.promptUserAuthorize(code);
        String authorizeURL = String.format(URL,wxMpService.getWxMpConfigStorage().getAppId(), URLEncoder.encode(callback + "/wx/portal/public/callBack"));
        return TextBuilder.build("请点击链接授权：<a href=\"" + authorizeURL + "\">点我授权</a>", wxMpXmlMessage);
    }

    @Override
    public void registryAuthorize(WxOAuth2UserInfo zhCn) {
        // 更新用户信息
        String nickname = zhCn.getNickname();
        String openid = zhCn.getOpenid();
        String headImgUrl = zhCn.getHeadImgUrl();
        Integer sex = zhCn.getSex();

        // 更新用户信息
        User user = userService.queryUserByOpenID(openid);
        user.setName(nickname);
        user.setAvatar(headImgUrl);
        user.setSex(sex);
        String code = OPENID_CODE_MAP.remove(openid);
        userDao.updateById(user);
        // 为用户配置权限
        userRoleService.genCommonRole(user.getId());

        // 完成登录授权
        customWebSocketService.authorize(user.getId(), code);

        // 异步发放物品
        threadPoolTaskExecutor.execute(() -> userBackpackService.acquireItem(user.getId(),
                ItemTypeEnum.MODIFY_NAME_CARD,
                System.currentTimeMillis(),
                ItemEnum.MODIFY_NAME_CARD.getId()));
    }


    /**
     * 得到 code，在生产环境下很有可能是新用户第一次扫码，所以这里需要转换
     * @param wxMpXmlMessage
     * @return
     */
    private String getEventKey(WxMpXmlMessage wxMpXmlMessage) {
        //扫码关注的渠道事件有前缀，需要去除
        return wxMpXmlMessage.getEventKey().replace("qrscene_", "");
    }
}
